package com.houkunlin.knife4j;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.TypeResolver;
import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.Set;

import static springfox.documentation.schema.AlternateTypeRules.newRule;

/**
 * @author HouKunLin
 */
@ConditionalOnClass({Pageable.class, Sort.class, IPage.class, OrderItem.class, OpenApiExtensionResolver.class})
@Component
public class SpringDataMyBatisDocketCustomizer implements DocketCustomizer {
    protected final TypeResolver typeResolver;
    protected final ResourceLoader resourceLoader;
    @Setter
    @Getter
    protected String packages;

    public SpringDataMyBatisDocketCustomizer(TypeResolver typeResolver, ResourceLoader resourceLoader) {
        this.typeResolver = typeResolver;
        this.resourceLoader = resourceLoader;
        this.packages = "com.houkunlin.wake.lan";
    }

    @Override
    public void customize(Docket docket) {
        assert resourceLoader != null;
        final ClassLoader classLoader = resourceLoader.getClassLoader();
        assert classLoader != null;

        final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(TableName.class));
        final Set<BeanDefinition> components = provider.findCandidateComponents(packages);
        for (BeanDefinition component : components) {
            try {
                final Class<?> loadClass = classLoader.loadClass(component.getBeanClassName());
                ResolvedType resolve = typeResolver.resolve(IPage.class, loadClass);
                docket.alternateTypeRules(newRule(resolve, PageableModel.class));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        docket.alternateTypeRules(newRule(IPage.class, PageableModel.class, 1));
        docket.alternateTypeRules(newRule(OrderItem.class, PageableSortModel.class, 1));
    }
}
